import java.awt.Point;
import java.util.ArrayList;

import javax.activity.InvalidActivityException;

public abstract class Agent extends MapObject {

	int fullEnergy = 20;
	
	private ClipsDecisionProvider provider;

	public abstract void makeMove();

	public ClipsDecisionProvider getProvider() {
		return provider;
	}

	public void setProvider(ClipsDecisionProvider provider) {
		this.provider = provider;
	}
 
	private int energy;
	
	private boolean isAlive = true;
	
	public boolean isAlive() {
		return isAlive;
	}

	public void setAlive(boolean isAlive) {
		this.isAlive = isAlive;
	}

	public void replenish()
	{
		this.setEnergy(fullEnergy);
	}
	
	public int getEnergy() {
		return energy;
	}

	public void setEnergy(int energy) {
		this.energy = energy;
	}
	
	public Agent(Point p) {
		super(p);
		setPosition(p); // ?
		setProvider(new ClipsDecisionProvider(this));
		setEnergy(fullEnergy);
	}
	
	public abstract MapObjectType getType();

	public void fight(long id) 
	{
		MapObject object = Main.getMap().getObjectOfId(id);
		if (isEnemy(object)) {
			Agent agent = (Agent) object;

			if(this.getEnergy() > agent.getEnergy())
			{
				agent.kill();
			}
			else
			{
				this.kill();
			}
		}
	}
	
	public void turnUndead()
	{
		Point p = getPosition();
		Main.getMap().getMap()[p.y][p.x] = new BlankSpace((Point) p.clone());
		if (getType() == MapObjectType.Human) {
			long newId = this.getId();
			Main.getMap().getAgents().remove(this);
			Zombie zombie = new Zombie(p);
			zombie.setId(newId);
			
			Main.getMap().getAgents().add(zombie);	
		}
	}
	
	protected boolean isEnemy(MapObject wo) {
		// TODO Auto-generated method stub
		return false;
	}

	public void kill() 
	{
		Point p = getPosition();
		Main.getMap().getMap()[p.y][p.x] = new BlankSpace((Point) p.clone());
		if (getType() == MapObjectType.Human) {
			this.setAlive(false);
		}
		if (getType() == MapObjectType.Zombie) {
			this.setAlive(false);
		}
		if (getType() == MapObjectType.Machine) {
			this.setAlive(false);
		}
	}


	
	public ArrayList<Direction> isNextToEmptySpace() {
		ArrayList<Direction> directions = new ArrayList<Direction>();
		Point l = MapUtils.getAdjecentPoint(getPosition(), Direction.LEFT);
		Point r = MapUtils.getAdjecentPoint(getPosition(), Direction.RIGHT);
		Point u = MapUtils.getAdjecentPoint(getPosition(), Direction.UP);
		Point d = MapUtils.getAdjecentPoint(getPosition(), Direction.DOWN);

		MapObject wol = Main.getMap().getMap()[l.y][l.x];
		MapObject wor = Main.getMap().getMap()[r.y][r.x];
		MapObject wou = Main.getMap().getMap()[u.y][u.x];
		MapObject wod = Main.getMap().getMap()[d.y][d.x];

		if (wol.getType() == MapObjectType.EMPTY_SPACE) {
			directions.add(Direction.LEFT);
		}

		if (wor.getType() == MapObjectType.EMPTY_SPACE) {
			directions.add(Direction.RIGHT);
		}

		if (wou.getType() == MapObjectType.EMPTY_SPACE) {
			directions.add(Direction.UP);
		}

		if (wod.getType() == MapObjectType.EMPTY_SPACE) {
			directions.add(Direction.DOWN);
		}

		return directions;
	}

	public boolean isNextToTree() {
		Point l = MapUtils.getAdjecentPoint(getPosition(), Direction.LEFT);
		Point r = MapUtils.getAdjecentPoint(getPosition(), Direction.RIGHT);
		Point u = MapUtils.getAdjecentPoint(getPosition(), Direction.UP);
		Point d = MapUtils.getAdjecentPoint(getPosition(), Direction.DOWN);

		MapObject wol = Main.getMap().getMap()[l.y][l.x];
		MapObject wor = Main.getMap().getMap()[r.y][r.x];
		MapObject wou = Main.getMap().getMap()[u.y][u.x];
		MapObject wod = Main.getMap().getMap()[d.y][d.x];

		if (wol.getType() == MapObjectType.Tree) {
			return true;
		}

		if (wor.getType() == MapObjectType.Tree) {
			return true;
		}

		if (wou.getType() == MapObjectType.Tree) {
			return true;
		}

		if (wod.getType() == MapObjectType.Tree) {
			return true;
		}

		return false;
	}
	
	public void move(Direction direction) {
		try {
			switch (direction) {
			case LEFT:
				moveLeft();
				break;
			case RIGHT:
				moveRight();
				break;
			case UP:
				moveUp();
				break;
			case DOWN:
				moveDown();
				break;
			}
		} catch (InvalidActivityException iae) {
			iae.printStackTrace();
		}
	}

	private void moveLeft() throws InvalidActivityException {
		Point p = getPosition();
		try {
			if (Main.getMap().getMap()[p.y][p.x - 1].getType() == MapObjectType.EMPTY_SPACE) {
				Main.getMap().getMap()[p.y][p.x - 1] = this;

				Main.getMap().getMap()[p.y][p.x] = new BlankSpace(
						(Point) p.clone());
				p.x -= 1;
			}
		} catch (IndexOutOfBoundsException ioobe) {
			throw new InvalidActivityException("Cannot move left");
		}
	}

	private void moveRight() throws InvalidActivityException {
		Point p = getPosition();
		try {
			if (Main.getMap().getMap()[p.y][p.x + 1].getType() == MapObjectType.EMPTY_SPACE) {
				Main.getMap().getMap()[p.y][p.x + 1] = this;

				Main.getMap().getMap()[p.y][p.x] = new BlankSpace(
						(Point) p.clone());
				p.x += 1;
			}
		} catch (IndexOutOfBoundsException ioobe) {
			throw new InvalidActivityException("Cannot move right");
		}
	}

	private void moveUp() throws InvalidActivityException {
		Point p = getPosition();
		try {
			if (Main.getMap().getMap()[p.y - 1][p.x].getType() == MapObjectType.EMPTY_SPACE) {
				Main.getMap().getMap()[p.y - 1][p.x] = this;

				Main.getMap().getMap()[p.y][p.x] = new BlankSpace(
						(Point) p.clone());
				p.y -= 1;
			}
		} catch (IndexOutOfBoundsException ioobe) {
			throw new InvalidActivityException("Cannot move up");
		}
	}

	private void moveDown() throws InvalidActivityException {
		Point p = getPosition();
		try {
			if (Main.getMap().getMap()[p.y + 1][p.x].getType() == MapObjectType.EMPTY_SPACE) {
				Main.getMap().getMap()[p.y + 1][p.x] = this;

				Main.getMap().getMap()[p.y][p.x] = new BlankSpace(
						(Point) p.clone());
				p.y += 1;
			}
		} catch (IndexOutOfBoundsException ioobe) {
			throw new InvalidActivityException("Cannot move down");
		}
	}
	
	

}
